"""增强版商品搜索爬虫"""

import time
import random
import logging
import json
from typing import List, Dict, Optional, Tuple
from urllib.parse import urljoin, urlparse, parse_qs

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException, NoSuchElementException

from .login_handler import LoginHandler
from .anti_crawler import AntiCrawlerHandler


class EnhancedSpider:
    """增强版商品搜索爬虫"""
    
    def __init__(self, platform: str = '1688', headless: bool = True, verbose: bool = False):
        """
        初始化增强版爬虫
        
        Args:
            platform: 平台名称 ('1688', 'taobao', 'jd')
            headless: 是否无头模式
            verbose: 是否详细输出
        """
        self.platform = platform
        self.headless = headless
        self.verbose = verbose
        self.driver = None
        self.login_handler = None
        self.anti_crawler = AntiCrawlerHandler()
        self.logger = self._setup_logger()
        
        # 平台特定配置
        self.platform_configs = {
            '1688': {
                'search_url_template': 'https://s.1688.com/selloffer/offer_search.htm?keywords={keyword}&n=y&pageSize=60&page={page}',
                'product_selectors': {
                    'container': '.offer-item, .sm-offer-item, [class*="offer"][class*="item"]',
                    'title': '.offer-title a, .title a, [class*="title"] a',
                    'price': '.price-num, .offer-price, [class*="price"]',
                    'link': 'a[href*="detail"], .offer-title a, .title a',
                    'image': 'img[src*="img.1688"], .offer-img img, [class*="img"] img',
                    'sales': '.sale-num, .trade-num, [class*="sale"]',
                    'location': '.location, .area, [class*="location"]',
                    'supplier': '.company-name, .supplier, [class*="company"]',
                    'moq': '.moq, .min-order, [class*="moq"]'
                },
                'next_page_selectors': ['.next', '.sm-pagination-next', '[class*="next"]'],
                'no_results_indicators': ['没有找到', '暂无商品', 'no result']
            },
            'taobao': {
                'search_url_template': 'https://s.taobao.com/search?q={keyword}&s={start}',
                'product_selectors': {
                    'container': '.item, .Card--mainPicAndDesc, [class*="item"]',
                    'title': '.title a, .Card--mainPicAndDesc a, [class*="title"] a',
                    'price': '.price, .priceInt, [class*="price"]',
                    'link': 'a[href*="item.taobao"], .title a',
                    'image': 'img[src*="img.alicdn"], .pic img',
                    'sales': '.deal-cnt, .sale-count, [class*="sale"]',
                    'location': '.location, .area',
                    'supplier': '.shop, .shopname',
                    'moq': ''
                },
                'next_page_selectors': ['.next', '.icon-btn-next'],
                'no_results_indicators': ['没有找到', '暂无商品']
            },
            'jd': {
                'search_url_template': 'https://search.jd.com/Search?keyword={keyword}&page={page}',
                'product_selectors': {
                    'container': '.gl-item, .p-item, [class*="item"]',
                    'title': '.p-name a, .gl-item .p-name a',
                    'price': '.p-price, .price',
                    'link': 'a[href*="item.jd"], .p-name a',
                    'image': 'img[src*="img.jd"], .p-img img',
                    'sales': '.p-commit, .sale-count',
                    'location': '.p-shop',
                    'supplier': '.p-shop a',
                    'moq': ''
                },
                'next_page_selectors': ['.pn-next', '.next'],
                'no_results_indicators': ['没有找到', '暂无商品']
            }
        }
    
    def _setup_logger(self) -> logging.Logger:
        """设置日志记录器"""
        logger = logging.getLogger(f"{__name__}.{self.platform}")
        logger.setLevel(logging.INFO if self.verbose else logging.WARNING)
        
        if not logger.handlers:
            handler = logging.StreamHandler()
            formatter = logging.Formatter(
                '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
            )
            handler.setFormatter(formatter)
            logger.addHandler(handler)
        
        return logger
    
    def initialize_driver(self) -> bool:
        """
        初始化WebDriver
        
        Returns:
            bool: 是否成功初始化
        """
        try:
            self.driver = self.anti_crawler.create_driver(
                headless=self.headless
            )
            
            # 初始化登录处理器
            self.login_handler = LoginHandler(
                driver=self.driver,
                platform=self.platform,
                verbose=self.verbose
            )
            
            self.logger.info(f"WebDriver初始化成功 - 平台: {self.platform}")
            return True
            
        except Exception as e:
            self.logger.error(f"WebDriver初始化失败: {e}")
            return False
    
    def search_products(self, keyword: str, max_pages: int = 3, 
                       filter_guangzhou: bool = False, sort_by_sales: bool = False) -> List[Dict]:
        """
        搜索商品
        
        Args:
            keyword: 搜索关键词
            max_pages: 最大页数
            filter_guangzhou: 是否筛选广州发货
            sort_by_sales: 是否按销量排序
            
        Returns:
            List[Dict]: 商品信息列表
        """
        if not self.driver:
            if not self.initialize_driver():
                return []
        
        all_products = []
        
        try:
            # 建立会话
            if not self.login_handler.establish_session():
                self.logger.warning("会话建立失败，尝试直接搜索")
            
            # 尝试从首页搜索
            homepage_search_success = self.login_handler.search_from_homepage(keyword)
            
            if homepage_search_success:
                self.logger.info("从首页搜索成功")
                # 处理搜索页面可能的登录要求
                self.login_handler.handle_search_page_login()
                
                # 从当前页面开始提取商品
                products = self._extract_products_from_current_page()
                if products:
                    all_products.extend(products)
                    self.logger.info(f"从首页搜索获取到 {len(products)} 个商品")
                
                # 继续爬取后续页面
                for page in range(2, max_pages + 1):
                    if not self._navigate_to_next_page():
                        break
                    
                    time.sleep(self.anti_crawler.get_random_delay())
                    
                    products = self._extract_products_from_current_page()
                    if products:
                        all_products.extend(products)
                        self.logger.info(f"第{page}页获取到 {len(products)} 个商品")
                    else:
                        self.logger.info(f"第{page}页无商品，停止爬取")
                        break
            else:
                # 首页搜索失败，使用直接URL搜索
                self.logger.info("首页搜索失败，使用直接URL搜索")
                all_products = self._search_by_direct_url(keyword, max_pages)
            
            # 后处理
            if filter_guangzhou:
                all_products = self._filter_guangzhou_products(all_products)
            
            if sort_by_sales:
                all_products = self._sort_by_sales(all_products)
            
            self.logger.info(f"搜索完成，共获取 {len(all_products)} 个商品")
            return all_products
            
        except Exception as e:
            self.logger.error(f"搜索商品时出错: {e}")
            return all_products
    
    def _search_by_direct_url(self, keyword: str, max_pages: int) -> List[Dict]:
        """
        通过直接URL搜索商品
        
        Args:
            keyword: 搜索关键词
            max_pages: 最大页数
            
        Returns:
            List[Dict]: 商品信息列表
        """
        all_products = []
        config = self.platform_configs.get(self.platform, self.platform_configs['1688'])
        
        for page in range(1, max_pages + 1):
            try:
                # 构建搜索URL
                if self.platform == 'taobao':
                    start = (page - 1) * 44  # 淘宝每页44个商品
                    search_url = config['search_url_template'].format(
                        keyword=keyword, start=start
                    )
                else:
                    search_url = config['search_url_template'].format(
                        keyword=keyword, page=page
                    )
                
                self.logger.info(f"访问第{page}页: {search_url}")
                self.driver.get(search_url)
                
                # 等待页面加载
                time.sleep(self.anti_crawler.get_random_delay())
                
                # 处理可能的登录要求
                self.login_handler.handle_search_page_login()
                
                # 提取商品信息
                products = self._extract_products_from_current_page()
                if products:
                    all_products.extend(products)
                    self.logger.info(f"第{page}页获取到 {len(products)} 个商品")
                else:
                    self.logger.info(f"第{page}页无商品，停止爬取")
                    break
                
                # 检查是否有下一页
                if not self._has_next_page():
                    self.logger.info("已到达最后一页")
                    break
                
            except Exception as e:
                self.logger.error(f"爬取第{page}页时出错: {e}")
                continue
        
        return all_products
    
    def _extract_products_from_current_page(self) -> List[Dict]:
        """
        从当前页面提取商品信息
        
        Returns:
            List[Dict]: 商品信息列表
        """
        products = []
        config = self.platform_configs.get(self.platform, self.platform_configs['1688'])
        
        try:
            # 等待商品容器加载
            WebDriverWait(self.driver, 10).until(
                EC.presence_of_element_located((By.CSS_SELECTOR, config['product_selectors']['container']))
            )
            
            # 查找所有商品容器
            product_elements = self.driver.find_elements(
                By.CSS_SELECTOR, config['product_selectors']['container']
            )
            
            self.logger.info(f"找到 {len(product_elements)} 个商品元素")
            
            for element in product_elements:
                try:
                    product = self._extract_product_info(element, config['product_selectors'])
                    if product and product.get('title'):
                        products.append(product)
                except Exception as e:
                    self.logger.debug(f"提取单个商品信息时出错: {e}")
                    continue
            
        except TimeoutException:
            self.logger.warning("等待商品加载超时")
            # 检查是否为无结果页面
            page_source = self.driver.page_source.lower()
            for indicator in config['no_results_indicators']:
                if indicator in page_source:
                    self.logger.info("检测到无搜索结果")
                    return []
        
        except Exception as e:
            self.logger.error(f"提取商品信息时出错: {e}")
        
        return products
    
    def _extract_product_info(self, element, selectors: Dict[str, str]) -> Optional[Dict]:
        """
        从商品元素中提取信息
        
        Args:
            element: 商品元素
            selectors: 选择器配置
            
        Returns:
            Optional[Dict]: 商品信息
        """
        product = {}
        
        try:
            # 提取标题
            title_element = self._find_element_in_container(element, selectors['title'])
            if title_element:
                product['title'] = title_element.get_attribute('title') or title_element.text.strip()
            
            # 提取链接
            link_element = self._find_element_in_container(element, selectors['link'])
            if link_element:
                href = link_element.get_attribute('href')
                if href:
                    product['link'] = urljoin(self.driver.current_url, href)
            
            # 提取价格
            price_element = self._find_element_in_container(element, selectors['price'])
            if price_element:
                price_text = price_element.text.strip()
                product['price'] = self._clean_price(price_text)
            
            # 提取图片
            image_element = self._find_element_in_container(element, selectors['image'])
            if image_element:
                src = image_element.get_attribute('src') or image_element.get_attribute('data-src')
                if src:
                    product['image'] = src
            
            # 提取销量
            if selectors['sales']:
                sales_element = self._find_element_in_container(element, selectors['sales'])
                if sales_element:
                    sales_text = sales_element.text.strip()
                    product['sales'] = self._clean_sales(sales_text)
            
            # 提取发货地
            if selectors['location']:
                location_element = self._find_element_in_container(element, selectors['location'])
                if location_element:
                    product['location'] = location_element.text.strip()
            
            # 提取供应商
            if selectors['supplier']:
                supplier_element = self._find_element_in_container(element, selectors['supplier'])
                if supplier_element:
                    product['supplier'] = supplier_element.text.strip()
            
            # 提取最小起订量（1688特有）
            if selectors['moq']:
                moq_element = self._find_element_in_container(element, selectors['moq'])
                if moq_element:
                    product['moq'] = moq_element.text.strip()
            
            return product if product.get('title') else None
            
        except Exception as e:
            self.logger.debug(f"提取商品信息时出错: {e}")
            return None
    
    def _find_element_in_container(self, container, selector: str):
        """
        在容器中查找元素
        
        Args:
            container: 容器元素
            selector: CSS选择器
            
        Returns:
            元素或None
        """
        try:
            return container.find_element(By.CSS_SELECTOR, selector)
        except NoSuchElementException:
            return None
    
    def _clean_price(self, price_text: str) -> str:
        """
        清理价格文本
        
        Args:
            price_text: 原始价格文本
            
        Returns:
            str: 清理后的价格
        """
        import re
        # 移除非数字和小数点的字符，保留价格数字
        price_match = re.search(r'[\d,]+\.?\d*', price_text.replace('，', ','))
        return price_match.group() if price_match else price_text
    
    def _clean_sales(self, sales_text: str) -> str:
        """
        清理销量文本
        
        Args:
            sales_text: 原始销量文本
            
        Returns:
            str: 清理后的销量
        """
        import re
        # 提取数字
        sales_match = re.search(r'\d+', sales_text)
        return sales_match.group() if sales_match else sales_text
    
    def _navigate_to_next_page(self) -> bool:
        """
        导航到下一页
        
        Returns:
            bool: 是否成功导航
        """
        try:
            config = self.platform_configs.get(self.platform, self.platform_configs['1688'])
            
            for selector in config['next_page_selectors']:
                try:
                    next_button = self.driver.find_element(By.CSS_SELECTOR, selector)
                    if next_button.is_displayed() and next_button.is_enabled():
                        next_button.click()
                        time.sleep(2)
                        return True
                except NoSuchElementException:
                    continue
            
            return False
            
        except Exception as e:
            self.logger.error(f"导航到下一页时出错: {e}")
            return False
    
    def _has_next_page(self) -> bool:
        """
        检查是否有下一页
        
        Returns:
            bool: 是否有下一页
        """
        try:
            config = self.platform_configs.get(self.platform, self.platform_configs['1688'])
            
            for selector in config['next_page_selectors']:
                try:
                    next_button = self.driver.find_element(By.CSS_SELECTOR, selector)
                    if next_button.is_displayed() and next_button.is_enabled():
                        return True
                except NoSuchElementException:
                    continue
            
            return False
            
        except Exception as e:
            self.logger.debug(f"检查下一页时出错: {e}")
            return False
    
    def _filter_guangzhou_products(self, products: List[Dict]) -> List[Dict]:
        """
        筛选广州发货的商品
        
        Args:
            products: 商品列表
            
        Returns:
            List[Dict]: 筛选后的商品列表
        """
        guangzhou_products = []
        guangzhou_keywords = ['广州', '广东', 'guangzhou']
        
        for product in products:
            location = product.get('location', '').lower()
            if any(keyword in location for keyword in guangzhou_keywords):
                guangzhou_products.append(product)
        
        self.logger.info(f"筛选广州发货商品: {len(guangzhou_products)}/{len(products)}")
        return guangzhou_products
    
    def _sort_by_sales(self, products: List[Dict]) -> List[Dict]:
        """
        按销量排序商品
        
        Args:
            products: 商品列表
            
        Returns:
            List[Dict]: 排序后的商品列表
        """
        def get_sales_number(product):
            sales = product.get('sales', '0')
            try:
                # 提取数字
                import re
                match = re.search(r'\d+', str(sales))
                return int(match.group()) if match else 0
            except:
                return 0
        
        sorted_products = sorted(products, key=get_sales_number, reverse=True)
        self.logger.info(f"按销量排序完成: {len(sorted_products)} 个商品")
        return sorted_products
    
    def close(self):
        """关闭浏览器"""
        if self.driver:
            try:
                self.driver.quit()
                self.logger.info("浏览器已关闭")
            except Exception as e:
                self.logger.error(f"关闭浏览器时出错: {e}")
    
    def __enter__(self):
        """上下文管理器入口"""
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        """上下文管理器出口"""
        self.close()